from sys import argv
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

class MyPyOpenGLTest:
    def __init__(self, width=640, height=480, title='选择物体'):
        glutInit(len(argv), argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        glutInitWindowSize(width, height)
        glutInitWindowPosition(350, 200)
        self.window = glutCreateWindow(title.encode('gbk'))
        glutDisplayFunc(self.draw)
        glutMouseFunc(self.mouse_downup)
        
        self.initGL(width, height)
        # 要绘制的三维物体
        self.objects = ('', '球', '立方体', '茶壶')

    def initGL(self, width, height):
        # 初始化窗口背景为灰色
        glClearColor(0.6, 0.6, 0.6, 1)
        # 启用深度测试
        glEnable(GL_DEPTH_TEST)
        glClearDepth(5)
        glDepthFunc(GL_LESS)
        
        # 设置光滑渲染模式
        glShadeModel(GL_SMOOTH)
        glEnable(GL_POINT_SMOOTH)
        glEnable(GL_LINE_SMOOTH)
        glEnable(GL_POLYGON_SMOOTH)        
        glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
        glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST)

        # 设置光照效果
        glLightfv(GL_LIGHT0, GL_POSITION, (0, 3, 3, 0))
        glLightfv(GL_LIGHT0, GL_AMBIENT, (0.1, 0.1, 0.1, 1))
        glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.6, 0.6, 0.6, 1))
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        # 使得材质对当前光照进行跟踪
        glEnable(GL_COLOR_MATERIAL)
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

        glMatrixMode(GL_PROJECTION)
        gluPerspective(45.0, width/height, 1, 100)
        glMatrixMode(GL_MODELVIEW)

    def mouse_downup(self, button, state, x, y):
        if button==GLUT_LEFT_BUTTON and state==GLUT_UP:
            self.do_selection(x, y)

    def do_selection(self, x, y):
        selection_buffer = glSelectBuffer(16)
        viewport = glGetIntegerv(GL_VIEWPORT)
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glRenderMode(GL_SELECT)
        glLoadIdentity()
        gluPickMatrix(x, viewport[3] - y, 2, 2, viewport)
        aspect = viewport[2] / viewport[3]
        gluPerspective(45, aspect, 1, 100)
        self.draw()
        hits = glRenderMode(GL_RENDER)
        if hits:
            label = self.objects[selection_buffer[3]]
            glutSetWindowTitle(f'选择物体-选中了{label}'.encode('gbk'))
        else:
            glutSetWindowTitle("选择物体-没选择任何物体".encode('gbk'))

        glMatrixMode(GL_PROJECTION)
        glPopMatrix()

    def draw(self):
        # 每次绘制图形之前清除颜色缓冲区和深度缓冲区中的信息
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 切换到模型观察矩阵，才能正确绘制图形
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glInitNames()
        glPushName(0)

        glColor3f(1, 0, 0)
        glPushMatrix()
        glTranslatef(-10, 0, -35)
        glLoadName(self.objects.index('球'))
        glutSolidSphere(4, 30, 30)
        glPopMatrix()

        glColor3f(0, 1, 0)
        glPushMatrix()
        glTranslatef(0, 0, -35)
        glRotatef(30, 1, 6, 5)
        glLoadName(self.objects.index('立方体'))
        glutSolidCube(5)
        glPopMatrix()

        glColor3f(0, 1, 1)
        glPushMatrix()
        glTranslatef(10, 0, -35)
        glRotatef(30, 1, 7, 8)
        glLoadName(self.objects.index('茶壶'))
        glutSolidTeapot(4)
        glPopMatrix()

        # 交换缓冲区，更新图形
        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()

if __name__ == '__main__':
    MyPyOpenGLTest().mainloop()
